#[derive(Debug)]
struct Machine {
    instructions: Vec<i32>,
    input: Vec<i32>,
    output: Vec<i32>,
    ptr: usize,
}

struct Instruction {
    code: u8,
    mode1: u8,
    mode2: u8,
}

impl Machine {
    fn new(instructions: Vec<i32>, input: Vec<i32>, output: Vec<i32>) -> Self {
        Machine {
            instructions,
            input,
            output,
            ptr: 0usize,
        }
    }

    fn run(&mut self) -> i32 {
        let len = self.instructions.len();
        while len > self.ptr {
            let instruction = self.read();
            match instruction.code {
                99 => {
                    break;
                }
                1 => {
                    self.sum(instruction);
                }
                2 => {
                    self.mul(instruction);
                }
                3 => {
                    self.input();
                }
                4 => {
                    self.output(instruction);
                }
                5 => {
                    self.jtrue(instruction);
                }
                6 => {
                    self.jfalse(instruction);
                }
                7 => {
                    self.lt(instruction);
                }
                8 => {
                    self.eq(instruction);
                }
                _ => {
                    println!("{:?}", self);
                    panic!("Wtf?");
                }
            }
        }
        *self.output.last().unwrap()
    }

    fn read(&mut self) -> Instruction {
        let instruction = format!("{:0>5}", self.instructions[self.ptr]);
        Instruction {
            mode2: instruction[1..2].parse::<u8>().expect("Cannot parse as u8"),
            mode1: instruction[2..3].parse::<u8>().expect("Cannot parse as u8"),
            code: instruction[3..5].parse::<u8>().expect("Cannot parse as u8"),
        }
    }

    fn get(&self, pointer: usize, mode: u8) -> i32 {
        match mode {
            0 => self.instructions[self.instructions[pointer] as usize],
            1 => self.instructions[pointer],
            _ => {
                panic!("Unknown instruction mode");
            }
        }
    }

    fn sum(&mut self, instruction: Instruction) {
        let address = self.instructions[self.ptr + 3] as usize;
        self.instructions[address] =
            self.get(self.ptr + 1, instruction.mode1) + self.get(self.ptr + 2, instruction.mode2);
        self.ptr += 4;
    }

    fn mul(&mut self, instruction: Instruction) {
        let address = self.instructions[self.ptr + 3] as usize;
        self.instructions[address] =
            self.get(self.ptr + 1, instruction.mode1) * self.get(self.ptr + 2, instruction.mode2);
        self.ptr += 4;
    }

    fn input(&mut self) {
        let address = self.instructions[self.ptr + 1] as usize;
        self.instructions[address] = self.input.remove(0);
        self.ptr += 2;
    }

    fn output(&mut self, instruction: Instruction) {
        self.output.push(self.get(self.ptr + 1, instruction.mode1));
        self.ptr += 2;
    }

    fn jtrue(&mut self, instruction: Instruction) {
        if self.get(self.ptr + 1, instruction.mode1) != 0 {
            self.ptr = self.get(self.ptr + 2, instruction.mode2) as usize;
        } else {
            self.ptr += 3;
        }
    }

    fn jfalse(&mut self, instruction: Instruction) {
        if self.get(self.ptr + 1, instruction.mode1) == 0 {
            self.ptr = self.get(self.ptr + 2, instruction.mode2) as usize;
        } else {
            self.ptr += 3;
        }
    }

    fn lt(&mut self, instruction: Instruction) {
        let address = self.instructions[self.ptr + 3] as usize;
        if self.get(self.ptr + 1, instruction.mode1) < self.get(self.ptr + 2, instruction.mode2) {
            self.instructions[address] = 1i32;
        } else {
            self.instructions[address] = 0i32;
        }
        self.ptr += 4;
    }

    fn eq(&mut self, instruction: Instruction) {
        let address = self.instructions[self.ptr + 3] as usize;
        if self.get(self.ptr + 1, instruction.mode1) == self.get(self.ptr + 2, instruction.mode2) {
            self.instructions[address] = 1i32;
        } else {
            self.instructions[address] = 0i32;
        }
        self.ptr += 4;
    }
}

fn main() {
    let instructions = [
        3, 225, 1, 225, 6, 6, 1100, 1, 238, 225, 104, 0, 1101, 48, 82, 225, 102, 59, 84, 224, 1001,
        224, -944, 224, 4, 224, 102, 8, 223, 223, 101, 6, 224, 224, 1, 223, 224, 223, 1101, 92, 58,
        224, 101, -150, 224, 224, 4, 224, 102, 8, 223, 223, 1001, 224, 3, 224, 1, 224, 223, 223,
        1102, 10, 89, 224, 101, -890, 224, 224, 4, 224, 1002, 223, 8, 223, 1001, 224, 5, 224, 1,
        224, 223, 223, 1101, 29, 16, 225, 101, 23, 110, 224, 1001, 224, -95, 224, 4, 224, 102, 8,
        223, 223, 1001, 224, 3, 224, 1, 223, 224, 223, 1102, 75, 72, 225, 1102, 51, 8, 225, 1102,
        26, 16, 225, 1102, 8, 49, 225, 1001, 122, 64, 224, 1001, 224, -113, 224, 4, 224, 102, 8,
        223, 223, 1001, 224, 3, 224, 1, 224, 223, 223, 1102, 55, 72, 225, 1002, 174, 28, 224, 101,
        -896, 224, 224, 4, 224, 1002, 223, 8, 223, 101, 4, 224, 224, 1, 224, 223, 223, 1102, 57,
        32, 225, 2, 113, 117, 224, 101, -1326, 224, 224, 4, 224, 102, 8, 223, 223, 101, 5, 224,
        224, 1, 223, 224, 223, 1, 148, 13, 224, 101, -120, 224, 224, 4, 224, 1002, 223, 8, 223,
        101, 7, 224, 224, 1, 223, 224, 223, 4, 223, 99, 0, 0, 0, 677, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 1105, 0, 99999, 1105, 227, 247, 1105, 1, 99999, 1005, 227, 99999, 1005, 0, 256, 1105, 1,
        99999, 1106, 227, 99999, 1106, 0, 265, 1105, 1, 99999, 1006, 0, 99999, 1006, 227, 274,
        1105, 1, 99999, 1105, 1, 280, 1105, 1, 99999, 1, 225, 225, 225, 1101, 294, 0, 0, 105, 1, 0,
        1105, 1, 99999, 1106, 0, 300, 1105, 1, 99999, 1, 225, 225, 225, 1101, 314, 0, 0, 106, 0, 0,
        1105, 1, 99999, 8, 677, 226, 224, 102, 2, 223, 223, 1006, 224, 329, 101, 1, 223, 223, 107,
        677, 677, 224, 1002, 223, 2, 223, 1006, 224, 344, 101, 1, 223, 223, 8, 226, 677, 224, 102,
        2, 223, 223, 1006, 224, 359, 101, 1, 223, 223, 107, 226, 226, 224, 102, 2, 223, 223, 1005,
        224, 374, 1001, 223, 1, 223, 1108, 677, 226, 224, 1002, 223, 2, 223, 1006, 224, 389, 101,
        1, 223, 223, 107, 677, 226, 224, 102, 2, 223, 223, 1006, 224, 404, 1001, 223, 1, 223, 1107,
        226, 677, 224, 1002, 223, 2, 223, 1006, 224, 419, 1001, 223, 1, 223, 108, 677, 677, 224,
        102, 2, 223, 223, 1005, 224, 434, 1001, 223, 1, 223, 1008, 677, 226, 224, 1002, 223, 2,
        223, 1006, 224, 449, 1001, 223, 1, 223, 7, 226, 677, 224, 1002, 223, 2, 223, 1006, 224,
        464, 1001, 223, 1, 223, 1007, 677, 677, 224, 102, 2, 223, 223, 1005, 224, 479, 1001, 223,
        1, 223, 1007, 226, 226, 224, 1002, 223, 2, 223, 1005, 224, 494, 1001, 223, 1, 223, 108,
        226, 226, 224, 1002, 223, 2, 223, 1005, 224, 509, 1001, 223, 1, 223, 1007, 226, 677, 224,
        1002, 223, 2, 223, 1006, 224, 524, 101, 1, 223, 223, 1107, 677, 677, 224, 102, 2, 223, 223,
        1005, 224, 539, 101, 1, 223, 223, 1107, 677, 226, 224, 102, 2, 223, 223, 1005, 224, 554,
        1001, 223, 1, 223, 108, 677, 226, 224, 1002, 223, 2, 223, 1006, 224, 569, 1001, 223, 1,
        223, 1108, 226, 677, 224, 1002, 223, 2, 223, 1006, 224, 584, 101, 1, 223, 223, 8, 677, 677,
        224, 1002, 223, 2, 223, 1006, 224, 599, 1001, 223, 1, 223, 1008, 226, 226, 224, 102, 2,
        223, 223, 1006, 224, 614, 101, 1, 223, 223, 7, 677, 677, 224, 1002, 223, 2, 223, 1006, 224,
        629, 101, 1, 223, 223, 1008, 677, 677, 224, 102, 2, 223, 223, 1005, 224, 644, 101, 1, 223,
        223, 7, 677, 226, 224, 1002, 223, 2, 223, 1005, 224, 659, 101, 1, 223, 223, 1108, 226, 226,
        224, 102, 2, 223, 223, 1006, 224, 674, 1001, 223, 1, 223, 4, 223, 99, 226,
    ]
    .to_vec();
    println!("{}", Machine::new(instructions, vec![5], vec![]).run());
}
